// src/util.hpp
#pragma once // C++ 约定：防止头文件被重复包含

#include <iostream>
#include <string>
#include <fstream>      // C++ 文件流：std::ifstream, std::ofstream
#include <sstream>      // C++ 字符串流：std::stringstream
#include <unistd.h>     // POSIX API：access, mkdir
#include <sys/stat.h>   // POSIX API：stat, S_IRWXU
#include <memory>       // 智能指针：std::unique_ptr
#include <jsoncpp/json/json.h> // Jsoncpp 库

namespace aod {

//-----------------------------------------------------
// 文件实用工具类 (FileUtil)
// 封装 C++ 标准库和 POSIX API，简化文件操作。
//-----------------------------------------------------
class FileUtil {
public:
    // 构造函数：初始化要操作的文件/目录的路径
    FileUtil(const std::string& path) : _path(path) {}

    /**
     * @brief 检查文件或目录是否存在
     * @return 存在返回 true, 否则返回 false
     */
    bool Exists() {
        // access 是 C POSIX API，F_OK 模式只检查文件是否存在
        return (access(_path.c_str(), F_OK) == 0);
    }

    /**
     * @brief 创建一个目录
     * @return 成功返回 true, 失败返回 false
     */
    bool CreateDirectory() {
        if (Exists()) {
            return true; // 如果目录已存在，视为成功
        }
        // mkdir 是 C POSIX API，用于创建目录
        // 0777 是权限掩码 (rwx for owner, group, others)
        return (mkdir(_path.c_str(), 0777) == 0);
    }

    /**
     * @brief 向文件写入完整内容 (覆盖写入)
     * @param content 要写入的文件内容
     * @return 成功返回 true, 失败返回 false
     */
    bool SetContent(const std::string& content) {
        // std::ofstream (输出文件流)，以二进制模式打开
        std::ofstream ofs(_path, std::ios::binary);
        if (!ofs.is_open()) {
            std::cerr << "FileUtil::SetContent failed to open: " << _path << std::endl;
            return false;
        }
        
        // 写入字符串内容
        ofs.write(content.c_str(), content.length());
        
        if (!ofs.good()) {
            std::cerr << "FileUtil::Setcontent write error: " << _path << std::endl;
            ofs.close();
            return false;
        }
        
        ofs.close();
        return true;
    } 

    /**
     * @brief 从文件读取完整内容
     * @param content [输出] 读取到的文件内容，使用 C++ 引用传递 (&)
     * @return 成功返回 true, 失败返回 false
     */
    bool GetContent(std::string& content) {
        // std::ifstream (输入文件流)，以二进制模式打开
        std::ifstream ifs(_path, std::ios::binary);
        if (!ifs.is_open())  {
            std::cerr << "FileUtil::GetContent failed to open: " << _path << std::endl;
            return false;
        }

        // C++ 文件流技巧：一次性读取全部内容
        ifs.seekg(0, std::ios::end); // 移动到文件尾
        size_t size = ifs.tellg();   // 获取文件大小
        ifs.seekg(0, std::ios::beg); // 移回文件头

        content.resize(size);      // 调整 string 大小
        ifs.read(&content[0], size); // 读取全部内容
        
        // 检查读取状态 (允许读到文件尾 eof)
        if (!ifs.good() && !ifs.eof()) {
            std::cerr << "FileUtil::GetContent read error: " << _path << std::endl;
            ifs.close();
            return false;
        }

        ifs.close();
        return true;
    }

    /**
     * @brief 获取文件大小 (字节)
     * @return 文件大小，失败返回 0
     */
    size_t FileSize() {
        struct stat st; // POSIX stat 结构体
        if (stat(_path.c_str(), &st) < 0) {
            std::cerr << "FileUtil::FileSize failed to stat: " << _path << std::endl;
            return 0;
        }
        return st.st_size; // st_size 成员即为文件大小
    }

private:
    std::string _path;      // 文件或目录的路径
};

//-----------------------------------------------------
// Json 实用工具类 (JsonUtil)
// 封装 Jsoncpp 序列化/反序列化，确保 UTF-8 友好。
//-----------------------------------------------------
class JsonUtil {
public:
    /**
     * @brief 序列化：将 Json::Value 对象 转换为 字符串 (用于 HTTP 响应)
     * @param root 要序列化的 Json::Value (使用 const 引用，输入型)
     * @param str [输出] 序列化后的 JSON 字符串 (使用引用传递，输出型)
     * @return 成功返回 true, 失败返回 false
     */
    static bool Serialize(const Json::Value& root, std::string& str) {
        Json::StreamWriterBuilder wbuilder;
        
        // 关键配置：不缩进，不换行，实现网络高效传输。同时默认是 UTF-8 友好。
        wbuilder["indentation"] = ""; 

        std::stringstream ss;
        // 使用智能指针管理 StreamWriter，符合 C++ 资源管理规范
        std::unique_ptr<Json::StreamWriter> writer(wbuilder.newStreamWriter());

        if (writer->write(root, &ss) != 0) {
            std::cerr << "JsonUtil::Serialize write failed!" << std::endl;
            return false;
        }
        str = ss.str();
        return true;
    }

    /**
     * @brief 反序列化：将 字符串 转换为 Json::Value 对象 (用于 HTTP 请求)
     * @param root [输出] 解析后填充的 Json::Value (使用引用传递，输出型)
     * @param s 待解析的 JSON 字符串 (使用 const 引用，输入型)
     * @return 成功返回 true, 失败返回 false
     */
    static bool UnSerialize(Json::Value& root, const std::string& s) {
        Json::CharReaderBuilder rbuilder;
        // 使用智能指针管理 CharReader
        std::unique_ptr<Json::CharReader> reader(rbuilder.newCharReader());

        std::string errs;
        
        // 调用 C API 的解析函数
        bool ok = reader->parse(s.c_str(), s.c_str() + s.length(), &root, &errs);

        if (!ok || !errs.empty()) {
            std::cerr << "JsonUtil::UnSerialize parse failed: " << errs << std::endl;
            // 打印失败的 JSON 字符串，便于调试
            std::cerr << "JSON String: " << s << std::endl; 
            return false;
        }
        return true;
    }
};

} // namespace aod